#pragma once

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <functional>
#include <unistd.h>
#include "Log.hpp"
#include "Comment.hpp"
#include "InetAddr.hpp"
using namespace LogModule;

const static int backlog = 8;

string Func(string str, struct sockaddr_in addr)
{
    string s = "hello";
    return s + str;
}

class TcpServer : public NoCopy
{
private:
    using func_t = std::function<string(string, struct sockaddr_in)>;

public:
    TcpServer(uint16_t prot, func_t func = Func)
        : _func(func),
          _prot(prot)
    {
    }

    void Init()
    {
        // 创建套接字:数据类似为流式
        _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensockfd < 0)
        {
            LOG(LogLevel::ERROR) << "socket error";
            exit(SOCK_ERR);
        }
        LOG(LogLevel::INFO) << "socket success: " << _listensockfd; // 3

        // 绑定
        InetAddr inetaddr(_prot);
        int n = bind(_listensockfd, inetaddr.Getaddr(), inetaddr.Len());
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind error";
            exit(BIND_ERR);
        }
        LOG(LogLevel::INFO) << "bind success: " << _listensockfd; // 3

        // 将套接字设置为listen状态：TCP服务器处于listen状态下，才可以被连接
        int m = listen(_listensockfd, backlog);
        if (m < 0)
        {
            LOG(LogLevel::FATAL) << "listen error";
            exit(LISTEN_ERR);
        }
        LOG(LogLevel::INFO) << "listen success: " << _listensockfd; // 3
    }

    void Run()
    {
        while (true)
        {
            // 获取连接，建立通信（若获取连接失败，则再次进行获取）
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            // accept返回一个新的fd，由新的套接字提供服务
            _sockfd = accept(_listensockfd, (struct sockaddr *)&peer, &len);
            if (_sockfd < 0)
            {
                LOG(LogLevel::ERROR) << "accept error";
                continue;
            }

            // 连接获取成功，执行对应方法
            Service(peer);
            // 任务执行完毕
            close(_sockfd);
            break;
        }
    }

    void Service(struct sockaddr_in &peer)
    {
        while (true)
        {
            // 接收客户端信息
            // a. n>0: 读取成功
            // b. n<0: 读取失败
            // c. n==0: 对端把链接关闭了，读到了文件的结尾 --- pipe
            char buff[1024];
            ssize_t n = read(_sockfd, buff, sizeof(buff) - 1);
            if (n > 0)
            {
                buff[n] = 0;
                cout << "tcpclient say: " << buff << endl;

                // 调用方法
                string ret = _func(string(buff), peer);

                // 发送信息
                write(_sockfd, ret.c_str(), ret.size());
            }
            else if (n == 0)
            {
                LOG(LogLevel::INFO) << "读取到了文件末尾~";
                return;
            }
            else
            {
                LOG(LogLevel::ERROR) << "读取失败！";
                return;
            }
        }
    }

private:
    int _listensockfd;
    int _sockfd;
    uint16_t _prot;
    func_t _func;
};